package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/linclaus/stock/pkg/cache"

	"github.com/linclaus/stock/pkg/alertmanager"
	"github.com/linclaus/stock/pkg/grafana"

	"github.com/linclaus/stock/pkg/api"
	"github.com/linclaus/stock/pkg/channel"
	"github.com/linclaus/stock/pkg/db"
	"github.com/linclaus/stock/pkg/metric"
	"github.com/linclaus/stock/pkg/model"
	"github.com/linclaus/stock/pkg/prometheus"

	"github.com/linclaus/stock/pkg/common/util"
)

func main() {
	fmt.Println("Stock Started")
	// Set Args
	var port string
	var interval int
	var alwaysScrape bool
	flag.BoolVar(&alwaysScrape, "alwaysScrape", false, "Does always scrape")
	flag.StringVar(&port, "port", "8080", "The address of stock APP")
	flag.IntVar(&interval, "interval", 5, "The interval between two scrapes")
	flag.IntVar(&api.DefaultExpiredTime, "defaultExpiredTime", 7, "The default expire days of straties")
	flag.IntVar(&api.DefaultMaxStrategiesNum, "defaultMaxStrategiesNum", 3, "The default max num of straties")
	flag.StringVar(&db.MYSQL_CON, "mysqlCon", "root:123456@tcp(127.0.0.1:3306)/stock?charset=utf8", "Mysql Connetction String")
	flag.StringVar(&api.STOCK_FILE_PATH, "stockPath", "/home/linclaus/stock/config/stock/", "The code file path")
	flag.StringVar(&prometheus.PROMETHEUS_HOST, "prometheusHost", "http://localhost:9090", "Prometheus Host")
	flag.StringVar(&prometheus.RULE_FILE_PATH, "rulePath", "/home/linclaus/stock/config/prometheus/rules/", "Prometheus Rule Path")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaVer, "grafanaVersion", "5.x", "The Grafana version")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaAddr, "grafanaAddr", "http://localhost:3000", "The Grafana Address")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaAdminUser, "grafanaUser", "admin", "The Grafana User")
	flag.StringVar(&grafana.GrafanaArgs.GrafanaAdminPass, "grafanaPass", "GS2018niu!888", "The Grafana Password")
	flag.StringVar(&alertmanager.WEBHOOK_URL, "alertWebhook", "http://stock-weixin/alert", "The webhook of alert")
	flag.StringVar(&alertmanager.ALERTMANAGER_CONFIG_PATH, "alertmanagerConfigPath", "/home/linclaus/stock/config/alertmanager/", "The Alertmanager config path")
	flag.StringVar(&alertmanager.ALERTMANAGER_CONFIG_NAME, "alertmanagerConfigName", "alertmanager.yml", "The Alertmanager config name")
	flag.StringVar(&alertmanager.ALERTMANAGER_HOST, "alertmanagerHost", "http://localhost:9093", "Alertmanager host")
	flag.StringVar(&alertmanager.ALERTMANAGER_GROUP_INTERVAL, "groupInterval", "5m", "The Alertmanager group interval")
	flag.StringVar(&alertmanager.ALERTMANAGER_REPEAT_INTERVAL, "repeatInterval", "1d", "The Alertmanager repeat interval")

	flag.Parse()

	// Get os signal
	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, os.Kill)
	codes := initCodeSet()
	s := api.New(codes)
	//Init metrics
	channel.Init()

	util.SetByCodes(s.Codes.List(), cache.StockMap)
	//Init Grafana
	grafana.GrafanaArgs.PrometheusAddr = prometheus.PROMETHEUS_HOST
	grafana.GrafanaArgs.DataSourceName = "Prometheus"
	err := grafana.Initialize(grafana.GrafanaArgs)
	if err != nil {
		fmt.Printf("init grafana failed for reason: %s\n", err)
		return
	}
	go grafana.RefreshDashboardsByFolderId()

	//Start server
	go s.Start(":" + port)
	//Set stock message scrape interval
	ticker := time.NewTicker(time.Second * time.Duration(interval))
	scrapeFlag := true
	lastTime := util.GetStockTime("sh000001")
	for {
		select {
		case <-ticker.C:
			if alwaysScrape {
				fmt.Printf("Update %d Metrics\n", len(s.Codes.List()))
				util.SetByCodes(s.Codes.List(), cache.StockMap)
				break
			}

			currentTime := util.GetStockTime("sh000001")
			now := time.Now()
			todayMinutes := now.Hour()*60 + now.Minute()
			fmt.Printf("hour: %d, minute: %d, todayMinutes: %d\n", now.Hour(), now.Minute(), todayMinutes)
			fmt.Printf("lastTime: %s, currentTime: %s\n", lastTime, currentTime)
			if (todayMinutes > 9*60+30-1 && todayMinutes < 15*60+5) && !(strings.HasPrefix(lastTime, "15") && strings.HasPrefix(currentTime, "15")) {
				if !scrapeFlag {
					fmt.Println("Stock is opened")
					metric.RegistMetric()
					scrapeFlag = true
				}
				fmt.Printf("Update %d Metrics\n", len(s.Codes.List()))
				util.SetByCodes(s.Codes.List(), cache.StockMap)
			} else {
				if scrapeFlag {
					fmt.Println("Stock is closed")
					metric.UnRegistMetric()
					scrapeFlag = false
				}
			}
			lastTime = currentTime
		case signal := <-c:
			//Save stock message before exit
			fmt.Println("退出信号", signal)
			fmt.Println(strings.Join(s.Codes.List(), ","))
			fmt.Println(cache.StockMap)
			api.StoreStocks(cache.StockMap)
			return
		}
	}
}

func initCodeSet() *model.CodeSet {
	// Initial the monitor stock code
	file, err := os.OpenFile(api.STOCK_FILE_PATH+api.CODE_FILE_NAME, os.O_RDONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Println("文件打开失败", err)
	}
	buf := bufio.NewReader(file)

	codeStr := ""
	for {
		codeByte, _, err := buf.ReadLine()
		if err == io.EOF {
			break
		}
		codeStr = codeStr + string(codeByte)
	}

	file.Close()
	codes := strings.Split(codeStr, ",")
	cs := model.NewCodeSet()
	if len(codes) == 0 || codes[0] == "" {
		codes = []string{"sh000001", "sz399001"}
		cs.AddSet(codes)
		api.StoreCodes(cs)
		return cs
	}
	cs.AddSet(codes)
	return cs
}
